#include<iostream>
#include <pthread.h>
#include<iomanip>
#include <iostream>
#include<vector>
#include<sys/time.h>
#include <arm_neon.h>
using namespace std;
int taskNum = 1;
int pThreadNum = 1;
int n;
float** m;
void generate()
{
    for (int i = 0; i < n; i++)
    {
        m[i][i] = 1.0;
        for (int p = i + 1; p < n; p++)
        {
            m[i][p] = rand() % 100 + 1;
        }
    }
    for (int k = 0; k < n; k++)
    {
        for (int i = k + 1; i < n; i++)
        {
            for (int p = 0; p < n; p++)
            {
                m[i][p] += m[k][p];
            }
        }
    }
}
void show()
{
    for (int i = 0; i < n; i++)
    {
        for (int p = 0; p < n; p++)
        {
            cout << setw(5) << m[i][p] << " ";
        }
        cout << endl;
    }
}
void commonGaosi()
{
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            m[i][j] /= m[i][i];
        }
        for (int k = i + 1; k < n; k++)
        {
            for (int j = i + 1; j < n; j++)
            {
                m[k][j] -= m[i][j] * m[k][i];
            }
            m[k][i] = 0;
        }
    }
}
void init()
{
    m = new float* [n];
    for (int p = 0; p < n; p++)
    {
        m[p] = new float[n];
        for (int q = 0; q < n; q++)
        {
            m[p][q] = 0.0;
        }
    }
    generate();
}



typedef struct
{
    int k; 
    int t_id; 
}threadParam_t;



void* neonthreadFunc(void* param)
{
    threadParam_t* p = (threadParam_t*)param;
    int k = p->k;
    int t_id = p->t_id;
    int begin = k + t_id * taskNum + 1;
    

    int j = 0;
    float32x4_t t1, t2, vx, vaik;
    for (int i = begin; (i < begin + taskNum) && (i < n); i++)
    {
        vaik = vdupq_n_f32(m[i][k]);
        for (j = k + 1; j + 4 < n; j += 4)
        {
            t1 = vld1q_f32(&m[i][j]);
            t2 = vld1q_f32(&m[k][j]);
            vx = vmulq_f32(vaik, t2);
            t1 = vsubq_f32(t1, vx);
            vst1q_f32(&m[i][j], t1);
        }
        for (; j < n; j++)
        {
            m[i][j] = m[i][j] - m[i][k] * m[k][j];
        }
        m[i][k] = 0;
    }

    pthread_exit(NULL);
}


void* threadFunc(void* param)
{
    threadParam_t* p = (threadParam_t*)param;
    int k = p->k; 
    int t_id = p->t_id; 
    int begin = k + t_id * taskNum + 1;
    for (int i = begin; (i < begin + taskNum) && (i < n); i++)
    {
        for (int j = k + 1; j < n; j++)
        {
            m[i][j] = m[i][j] - m[i][k] * m[k][j];
        }
        m[i][k] = 0;
    }
    pthread_exit(NULL);
}


void gaosi(int type)
{
    for (int k = 0; k < n; k++)
    {
        for (int j = k + 1; j < n; j++)
        {
            m[k][j] = m[k][j] / m[k][k];
        }
        m[k][k] = 1;
        pthread_t* handle = new pthread_t[pThreadNum];
        threadParam_t* param = new threadParam_t[pThreadNum];
        for (int id = 0; id < pThreadNum; id++)
        {
            param[id].t_id = id;
            param[id].k = k;
        }
        for (int id = 0; id < pThreadNum; id++)
        {
            switch (type)
            {
            case 0:
                pthread_create(&handle[id], NULL, threadFunc, (void*)&param[id]);
                break;
            case 1:
                pthread_create(&handle[id], NULL, neonthreadFunc, (void*)&param[id]);
                break;
            }
        }
        for (int id = 0; id < pThreadNum; id++)
        {
            pthread_join(handle[id], NULL);
        }
    }
}
int main()
{
    pThreadNum = 10;

    struct timeval t1, t2;
    double timeuse;

    for (int i = 1; i <= 1; i++)
    {
        n = i * 10;
        taskNum = n / pThreadNum;
        init();
        gettimeofday(&t1, NULL);
        gaosi(0);
        gaosi(1);
        commonGaosi();
        gettimeofday(&t2, NULL);
        timeuse = (t2.tv_sec - t1.tv_sec) + (double)(t2.tv_usec - t1.tv_usec) / 1000000.0;
        cout << timeuse << endl;
    }
    return 0;
}